#include "../header/fudpServer.hpp"

queue<int> fudpServer::client_vector;

map<int,struct fudpServer::threadARG> fudpServer::runningThread;

// currently not multithead
fudpServer::fudpServer(){
    // MLOG("init server:"<<_ip);

    int check_ret;
    this->fd = socket(PF_INET,SOCK_DGRAM , 0);
    assert(this->fd >= 0);

    struct sockaddr_in address;
    bzero(&address,sizeof(address));

    //转换成网络地址
    address.sin_port = htons(fltp_port);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(INADDR_ANY);

    //绑定ip和端口
    check_ret = bind(this->fd,(struct sockaddr*)&address,sizeof(address));
    MLOG("check ret:"<<check_ret);
    assert(check_ret >= 0);

    // init valiable port
    for(int c1=1;c1<=10;c1++){
        client_vector.push(fltp_port+c1);
    }
}

// begin to listern
void fudpServer::listern(){
    MLOG("begin to listern the port"<<fltp_port);

        char buffer[max_datagram_size];
    while(1){

        struct sockaddr_in addressClient;
        socklen_t clientLen = sizeof(addressClient);
        //获取信息
        if(recvfrom(fd, buffer, max_datagram_size,0,(struct sockaddr*)&addressClient, &clientLen) == -1) 
        { 
           perror("Receive Data Failed:"); 
           exit(1); 
        }

        Datagram data(buffer);

        memset(buffer,0,sizeof(char)*max_datagram_size);
        
        data.getData(buffer);
        MLOG("get request: "<<data.getHeader().type<<endl
        <<"rsize:"<<data.getHeader().dataLength<<endl
        <<endl<<buffer<<":"<<buffer+10);
        
        // get the ask and begin to handshake
        handleHandshake(buffer, addressClient);

    }
}

void fudpServer::handleHandshake(char* _msg, struct sockaddr_in& addressClient) {
    // just send and recieved now
    // datagram_type::type_severACKReadyAndAsk
    Datagram data(type_severACKReadyAndAsk);

    int temp_port = client_vector.front();
    client_vector.pop();
    int newSocket = initSocket(temp_port);
    char str[10]={0};
    sprintf(str,"%d",temp_port);
    data.fillData(str,strlen(str),0);

    char buffer[max_datagram_size]={0};
    int rsize=data.get(buffer);
    if(sendto(fd,buffer,rsize,0,(struct sockaddr*)&addressClient,sizeof(addressClient))<0) {
        MLOG("failed type_severACKReadyAndAsk");
        handleClose(temp_port);
        return;
    } else {
        MLOG("succeed type_severACKReadyAndAsk");
        socklen_t clientLen = sizeof(addressClient);
        if(recvfrom(newSocket, buffer, max_datagram_size,0,(struct sockaddr*)&addressClient, &clientLen) == -1) { 
            MLOG("Receive Data Failed:"); 
            handleClose(temp_port);
            return;
        } else {
            MLOG("GET CLIENT's ack");
            // finish handshake begin to handle data
            // add it to running
            struct threadARG arg;
            arg.handler = this;
            arg.newSocket = newSocket;
            arg.addressClient = addressClient;
            arg.filename = _msg+10;
            arg.temp_port = temp_port;
            // _msg,newSocket, temp_port,addressClient
            runningThread[temp_port]=arg;

            pthread_t threadId;
            if(memcmp(_msg,method_send,sizeof(char)*4)==0){
                if(pthread_create(&threadId, NULL, handleSend, ((void*) (long) (temp_port)))!=0)
                {
                    handleClose(temp_port);
                }
            } else if(memcmp(_msg,method_get,sizeof(char)*4)==0) {
                if(pthread_create(&threadId, NULL, handleGet, ((void*) (long) (temp_port)))!=0)
                {
                    handleClose(temp_port);
                }
            } else {
                MLOG("ERROR CALL FROM CLIENT");
                handleClose(temp_port);
            }

        }
    }
}

// a function to handle a send
void* fudpServer::handleSend(void* _arg){
    MLOG("server: begin to handle send request");
    struct threadARG arg = runningThread[((int)  (long) (_arg))];

    fudpReciver freciver(arg.newSocket, arg.addressClient ,arg.filename);
    freciver.recieve();
    
    handleClose(arg.temp_port);
}

void* fudpServer::handleGet(void* _arg){
    struct threadARG arg = runningThread[((int)  (long) (_arg))];

    FUDP_Sender fsender(arg.newSocket,arg.addressClient,arg.filename);
    fsender.send();

    handleClose(arg.temp_port);
}

void fudpServer::handleClose(int port){
    // just close
    client_vector.push(port);
    close(runningThread[port].newSocket);
    runningThread.erase(port);

    MLOG("rec thread: close");
}

int fudpServer::initSocket(int port){
    int newfd = socket(PF_INET,SOCK_DGRAM , 0);
    assert(newfd >= 0);
    struct sockaddr_in address;
    bzero(&address,sizeof(address));
    //转换成网络地址
    address.sin_port = htons(port);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(INADDR_ANY);
    struct timeval timeout={SERVER_MAX_RTT};
    int check_ret = bind(newfd,(struct sockaddr*)&address,sizeof(address));
    MLOG("check ret:"<<check_ret);
    setsockopt(newfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(struct timeval));
    MLOG("NEW SOCKET_ID:"<<newfd);
    return newfd;
}
    